package io.github.mosiki.modules.spider.service.impl;


import io.github.mosiki.common.enums.ResultEnum;
import io.github.mosiki.common.exception.MagicxException;
import io.github.mosiki.common.utils.Constant;
import io.github.mosiki.common.utils.RandomUtil;
import io.github.mosiki.modules.spider.converter.SpiderTaskConverter;
import io.github.mosiki.modules.spider.domain.SpiderTask;
import io.github.mosiki.modules.spider.dto.SpiderTaskDTO;
import io.github.mosiki.modules.spider.monitor.MySpiderMonitor;
import io.github.mosiki.modules.spider.monitor.MySpiderStatus;
import io.github.mosiki.modules.spider.repository.SpiderTaskRepository;
import io.github.mosiki.modules.spider.service.SpiderTaskService;
import io.github.mosiki.modules.spider.service.WebMagicService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import us.codecraft.webmagic.Spider;

import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * 类名称：SpiderTaskServiceImpl
 * 类描述：爬虫任务
 * 创建人：WeJan
 * 创建时间：2018-07-17 21:08:08
 */
@Service("spiderTaskService")
@Slf4j
public class SpiderTaskServiceImpl implements SpiderTaskService {
    @Autowired
    private SpiderTaskRepository spiderTaskRepository;
    @Autowired
    private WebMagicService webMagicService;

    @Override
    public Page<SpiderTaskDTO> listSpiderTask(Map<String, Object> params, PageRequest pageRequest) {
        //TODO 参数没用上 动态查询
        Page<SpiderTask> all = spiderTaskRepository.findAll(pageRequest);
        List<SpiderTaskDTO> dtos = SpiderTaskConverter.conver(all.getContent());
        return new PageImpl<>(dtos, pageRequest, all.getTotalElements());
    }

    @Override
    public SpiderTaskDTO findById(Long id) {
        return SpiderTaskConverter.conver(spiderTaskRepository.findById(id).orElse(null));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SpiderTask saveSpiderTask(SpiderTaskDTO spiderTaskDTO) {
        spiderTaskDTO.setStatus(Constant.STATUS_OK);
        SpiderTask spiderTask = spiderTaskRepository.save(SpiderTaskConverter.conver(spiderTaskDTO));
        return spiderTask;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SpiderTask updateSpiderTask(SpiderTask spiderTask) {
        return spiderTaskRepository.save(spiderTask);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteBatchIds(List<Long> ids) {
        return spiderTaskRepository.deleteByIdIn(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void startTask(String taskId) {

        SpiderTask spiderTask = spiderTaskRepository.findById(Long.parseLong(taskId)).orElse(null);

        if (spiderTask == null) {
            throw new MagicxException(ResultEnum.TASK_NOT_EXIST);
        }

        // 启动爬虫 爬虫已启动且已在运行 抛出异常
        MySpiderStatus spiderTaskInstance = this.getSpiderTaskInstance(SpiderTaskConverter.conver(spiderTask));
        if (spiderTaskInstance != null && Spider.Status.Running.name().equals(spiderTaskInstance.getStatus())) {
            throw new MagicxException(ResultEnum.TASK_NOT_REPEAT_START);
        }

        spiderTask.setStartTime(new Date());
        spiderTask.setSpriderUuid(RandomUtil.getUUID());

        // 更新Task
        spiderTask = spiderTaskRepository.save(spiderTask);
        SpiderTaskDTO spiderTaskDTO = SpiderTaskConverter.conver(spiderTask);
        webMagicService.run(spiderTaskDTO, true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void stopTask(String taskId) {
        SpiderTask spiderTask = spiderTaskRepository.findById(Long.parseLong(taskId)).orElse(null);

        if (spiderTask == null) {
            throw new MagicxException(ResultEnum.TASK_NOT_EXIST);
        }

        // 停止爬虫    未启动为null/已启动且状态不为run 抛出异常
        MySpiderStatus spiderTaskInstance = this.getSpiderTaskInstance(SpiderTaskConverter.conver(spiderTask));
        if (spiderTaskInstance == null || spiderTaskInstance != null && !Spider.Status.Running.name().equals(spiderTaskInstance.getStatus())) {
            throw new MagicxException(ResultEnum.SPIDER_STATUS_ERROR);
        }

        // 修改任务状态
        spiderTask.setEndTime(new Date());

        // 更新Task状态
        spiderTask = spiderTaskRepository.save(spiderTask);
        webMagicService.stop(spiderTaskInstance);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void startBreakTask(String taskId) {
        SpiderTask spiderTask = spiderTaskRepository.findById(Long.parseLong(taskId)).orElse(null);

        if (spiderTask == null) {
            throw new MagicxException(ResultEnum.TASK_NOT_EXIST);
        }

        // 启动爬虫 爬虫已启动且已在运行 抛出异常
        MySpiderStatus spiderTaskInstance = this.getSpiderTaskInstance(SpiderTaskConverter.conver(spiderTask));
        if (spiderTaskInstance != null && spiderTaskInstance.getStatus().equals(Spider.Status.Running.name())) {
            throw new MagicxException(ResultEnum.TASK_NOT_REPEAT_START);
        }

        spiderTask.setStartTime(new Date());

        // 更新Task状态
        spiderTask = spiderTaskRepository.save(spiderTask);
        SpiderTaskDTO spiderTaskDTO = SpiderTaskConverter.conver(spiderTask);
        webMagicService.runBreak(spiderTaskDTO, true);
    }

    @Override
    public void setSpiderTaskRunState(SpiderTaskDTO spiderTaskDTO) {

        MySpiderStatus spiderStatus = this.getSpiderTaskInstance(spiderTaskDTO);
        if (spiderStatus == null) {
            spiderTaskDTO.setRunState(Spider.Status.Stopped.name());
        } else {
            spiderTaskDTO.setRunState(spiderStatus.getStatus());
        }
    }

    @Override
    public MySpiderStatus getSpiderTaskInstance(SpiderTaskDTO spiderTaskDTO) {
        MySpiderMonitor spiderMonitor = MySpiderMonitor.instance();
        Map<String, MySpiderStatus> spiderStatuses = spiderMonitor.getSpiderStatuses();
        MySpiderStatus spiderStatus = spiderStatuses.get(spiderTaskDTO.getSpriderUuid());

        if (spiderStatus != null) {
            log.info("爬取数量：{}，成功：{}，失败：{}", spiderStatus.getTotalPageCount(), spiderStatus.getSuccessPageCount(), spiderStatus.getErrorPageCount());
            return spiderStatus;
        }
        return null;
    }
}
